﻿/*************************************************************************************
 * 工    具：  HK_SimpleFrameSequence
 * 
 * 描    述：  HK_SimpleFrameSequence 是一个轻量化的 Unity 序列帧动画控制器，
 *            可自动适配 UI Image 和 SpriteRenderer 两种渲染模式，支持精确帧率控制与循环播放。
 *            提供一键式纹理优化功能（关闭 Mipmap/ReadWrite），并通过自动补充渲染组件和首帧同步简化使用流程
 * 
 * 版    本：  V1.2
 * 作    者：  京产肠饭
 * 
 * 创    建：  2022/07/30  V1.0
 *
 * 更    新：  2025/03/31  V1.1
 *             1.性能优化：将所有 List<> 替换为 数组，提高性能，并缓存数组长度，减少频繁访问
 *             2.功能优化：优化帧率计算方式，帧间隔更精确
 *             3.功能新增：同时支持 Image 和 SpriteRenderer 组件，提高兼容性
 *             4.功能优化：新增 Hierarchy 中的图标绘制，提供易用性
 *
 *             2025/06/03  V1.2
 *             1.Bug修复：frameRate 可能被误设为负值，导致计算时报除零错误，在Inspector中限制输入范围，最小为1f 
 *             2.功能新增：当手动给 frame_List 赋值时，自动同步首帧到渲染组件，避免手动设置
 *             3.功能新增：当给一个物体添加组件时，自动补充 Image 或 SpriteRenderer 组件，避免手动添加
 *             4.功能新增：新增“关闭所有序列帧的 Mipmap”按钮和“禁用所有序列帧的 Read/Write Enabled”，批量禁用关联纹理的Mipmap和Read/Write属性
 * 
 * 链    接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using UnityEngine;
using UnityEngine.UI;

namespace HKTools
{
    public class HK_SimpleFrameSequence : MonoBehaviour
    {
        [Header("是否自动播放："), SerializeField] bool isAutoPlay = false;
        [Header("是否循环播放："), SerializeField] bool isLoop = false;
        [Header("帧率："), SerializeField, Min(1f)] float frameRate = 25.0f;
        [Header("序列帧："), SerializeField] public Sprite[] frames;

        int frameCount = 0;             // 缓存总帧数（数组长度）

        Image image;
        SpriteRenderer spriteRenderer;
        bool isUseImage;                // 标记当前使用的组件类型

        bool isPlaying;                 // 播放状态标记
        int frameIndex = 0;             // 当前播放帧索引
        float timer;                     // 帧时间累加器

#if UNITY_EDITOR
        /// <summary>
        /// 编辑器模式下添加组件时自动补充渲染组件
        /// </summary>
        void Reset()
        {
            // 检测是否在Canvas下（包含父级）
            bool isInCanvas = GetComponentInParent<Canvas>() != null;

            if (isInCanvas)
            {
                // 无Image组件时自动添加（支持撤销）
                if (GetComponent<Image>() == null)
                {
                    UnityEditor.Undo.AddComponent<Image>(gameObject);
                }
            }
            else
            {
                // 无SpriteRenderer组件时自动添加（支持撤销）
                if (GetComponent<SpriteRenderer>() == null)
                {
                    UnityEditor.Undo.AddComponent<SpriteRenderer>(gameObject);
                }
            }
        }
#endif

#if UNITY_EDITOR
        /// <summary>
        /// 编辑器模式下自动同步首帧到渲染组件
        /// </summary>
        void OnValidate()
        {
            // 若序列帧未初始化或无内容，直接返回
            if (frames == null || frames.Length == 0) return;

            // 重新获取当前组件（避免Awake前变量未初始化的问题）
            Image currentImage = GetComponent<Image>();
            SpriteRenderer currentSpriteRenderer = GetComponent<SpriteRenderer>();

            // 优先处理Image组件（与Awake逻辑保持一致）
            if (currentImage != null)
            {
                // 仅当sprite未设置或不是首帧时赋值（避免重复操作）
                if (currentImage.sprite == null)
                {
                    currentImage.sprite = frames[0];
                }
            }
            // 若没有Image组件，处理SpriteRenderer
            else if (currentSpriteRenderer != null)
            {
                if (currentSpriteRenderer.sprite == null)
                {
                    currentSpriteRenderer.sprite = frames[0];
                }
            }
        }
#endif

        /// <summary>
        /// 初始化组件和初始状态
        /// </summary>
        void Awake()
        {
            image = GetComponent<Image>();
            spriteRenderer = GetComponent<SpriteRenderer>();

            isUseImage = image != null;

            if (image == null && spriteRenderer == null)
            {
                HKDebug.LogError("未找到Image或SpriteRenderer组件！");
                enabled = false;
                return;
            }

            if (frames == null || frames.Length == 0)
            {
                enabled = false;
                HKDebug.LogError("序列帧数组未初始化！");
                return;
            }

            frameCount = frames.Length;

            if (isUseImage)
                image.sprite = frames[0];
            else
                spriteRenderer.sprite = frames[0];

            frameIndex = 0;
            isPlaying = false;
            timer = 0;

            if (isAutoPlay)
            {
                isPlaying = true;
            }
        }

        /// <summary>
        /// 驱动动画更新的主循环
        /// </summary>
        void Update()
        {
            if (!isPlaying)
                return;

            // 帧间隔时间
            float targetDelta = 1f / frameRate;

            // 使用循环处理时间累积，避免大deltaTime时跳帧
            while (timer >= targetDelta)
            {
                timer -= targetDelta;
                frameIndex++;

                // 使用取模运算优化循环逻辑
                if (frameIndex >= frameCount)
                {
                    if (isLoop)
                    {
                        frameIndex %= frameCount; // 使用取模代替重置归零

                    }
                    else
                    {
                        frameIndex = frameCount - 1; // 非循环时停留在最后一帧
                        isPlaying = false;
                        break;
                    }
                }

                if (isUseImage)
                    image.sprite = frames[frameIndex];
                else
                    spriteRenderer.sprite = frames[frameIndex];
            }

            timer += Time.deltaTime; // 将累加放到循环后更准确
        }

        /// <summary>
        /// 开始播放动画（可控制循环模式）
        /// </summary>
        /// <param name="isLoop">是否循环播放</param>
        public void StartFramesAnim(bool isLoop)
        {
            if (image == null && spriteRenderer == null)
            {
                HKDebug.LogError("未找到Image或SpriteRenderer组件！");
                enabled = false;
                return;
            }

            if (frames == null || frames.Length == 0)
            {
                enabled = false;
                HKDebug.LogError("序列帧数组未初始化！");
                return;
            }

            this.isLoop = isLoop;

            if (isUseImage)
                image.sprite = frames[0];
            else
                spriteRenderer.sprite = frames[0];

            frameIndex = 0;
            isPlaying = true;
            timer = 0f;
        }

        /// <summary>
        /// 停止动画播放并重置到首帧
        /// </summary>
        public void StopFramesAnim()
        {
            if (image == null && spriteRenderer == null)
            {
                HKDebug.LogError("未找到Image或SpriteRenderer组件！");
                enabled = false;
                return;
            }

            if (frames == null || frames.Length == 0)
            {
                enabled = false;
                HKDebug.LogError("序列帧数组未初始化！");
                return;
            }

            if (isUseImage)
                image.sprite = frames[0];
            else
                spriteRenderer.sprite = frames[0];

            isPlaying = false;
        }
    }
}